#include "bytearray.h"
#include<string.h>   // memcpy
#include<fstream>    // ofstream
#include"log.h"
#include<iomanip>    // setw() setfill
namespace sylar{

static sylar::Logger::ptr g_logger = SYLAR_LOG_NAME("system");

static uint32_t EncodeZigzag32(const int32_t& v) {
    if(v < 0) {
        return ((uint32_t)(-v)) * 2 - 1;
    } else {
        return v * 2;
    }
}

static uint64_t EncodeZigzag64(const int64_t& v) {
    if(v < 0) {
        return ((uint64_t)(-v)) * 2 - 1;
    } else {
        return v * 2;
    }
}

static int32_t DecodeZigzag32(const uint32_t& v) {
    return (v >> 1) ^ -(v & 1);
}

static int64_t DecodeZigzag64(const uint64_t& v) {
    return (v >> 1) ^ -(v & 1);
}


ByteArray::Node::Node(size_t s): 
        ptr(new char[s]), next(nullptr), size(s){}

ByteArray::Node::Node(): 
        ptr(nullptr), next(nullptr), size(0){}

ByteArray::Node::~Node(){
    if(ptr){
        delete[] ptr;
    }
}

ByteArray::ByteArray(size_t base_size):
    m_baseSize(base_size),
    m_position(0),
    m_capacity(base_size),
    m_size(0),
    m_root(new Node(base_size)),
    m_cur(m_root){
 
}
ByteArray::~ByteArray(){
    Node* tmp = m_root;
    while(tmp){
        m_cur = tmp;
        tmp = tmp->next;
        delete m_cur;
    }
}



//写入固定长度int8_t类型的数据
//m_position += sizeof(value)
void ByteArray::writeFint8  (int8_t value){
	write(&value, sizeof(value));
}
void ByteArray::writeFuint8 (uint8_t value){
	write(&value, sizeof(value));
}

//写入固定长度int16_t类型的数据(大端/小端)
//m_position += sizeof(value)
void ByteArray::writeFint16 (int16_t value){
    // 如果和当前机器的字节序不同
    if(m_endian != SYLAR_BYTE_ORDER) {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}
void ByteArray::writeFuint16(uint16_t value){
    if(m_endian != SYLAR_BYTE_ORDER){
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

//写入固定长度int32_t类型的数据(大端/小端)
//m_position += sizeof(value)
void ByteArray::writeFint32 (int32_t value){
    if(m_endian != SYLAR_BYTE_ORDER) {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}
void ByteArray::writeFuint32(uint32_t value){
    if(m_endian != SYLAR_BYTE_ORDER) {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

//写入固定长度int64_t类型的数据(大端/小端)
//m_position += sizeof(value)
void ByteArray::writeFint64 (int64_t value){
    if(m_endian != SYLAR_BYTE_ORDER) {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}
void ByteArray::writeFuint64(uint64_t value){
    if(m_endian != SYLAR_BYTE_ORDER) {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

//写入有符号Varint32类型的数据， 没有F是可变长度压缩, 执行数据数据 32%7 = 4......1 所以最多占5个字节
//m_position += 实际占用内存(1 ~ 5) 
void ByteArray::writeInt32  (int32_t value){
	writeUint32(EncodeZigzag32(value));
}
void ByteArray::writeUint32 (uint32_t value){
    uint8_t tmp[5];
    uint8_t i = 0;
    while(value >= 0x80) {    // 80表示每个字节的标志位，标识整型是否结束
        tmp[i++] = (value & 0x7F) | 0x80;   // 存储这个字节的数据，低7位加标志位
        value >>= 7;          // 获取余下的值
    } 
    tmp[i++] = value;
    write(tmp, i);
}

//写入有符号Varint64类型的数据   64%7 = 9......1  最多占用10个字节
//m_position += 实际占用内存(1 ~ 10)
void ByteArray::writeInt64  (int64_t value){
	writeUint64(EncodeZigzag64(value));
}
void ByteArray::writeUint64 (uint64_t value){
    uint8_t tmp[10];
    uint8_t i = 0;
    while(value >= 0x80) {
        tmp[i++] = (value & 0x7F) | 0x80;
        value >>= 7;
    }
    tmp[i++] = value;
    write(tmp, i);
}

//写入float类型的数据，转换成uint32
//m_position += sizeof(value)  
void ByteArray::writeFloat  (float value){
    uint32_t v;
    memcpy(&v, &value, sizeof(value));
    writeFuint32(v);
}
void ByteArray::writeDouble (double value){
    uint32_t v;
    memcpy(&v, &value, sizeof(value));
    writeFuint64(v);
}

//写入std::string类型的数据,用uint16_t作为长度类型。先写入长度再写入数据
//m_position += 2 + value.size()
void ByteArray::writeStringF16(const std::string& value){
    writeFuint16(value.size());
    write(value.c_str(), value.size());
}
void ByteArray::writeStringF32(const std::string& value){
    writeFuint32(value.size());
    write(value.c_str(), value.size());
}
void ByteArray::writeStringF64(const std::string& value){
    writeFuint64(value.size());
    write(value.c_str(), value.size());
}

//写入std::string类型的数据,用无符号Varint64作为长度类型
//m_position += Varint64长度 + value.size()
void ByteArray::writeStringVint(const std::string& value){
    writeUint64(value.size());
    write(value.c_str(), value.size());
}

//写入std::string类型的数据,无长度
//m_position += value.size()
void ByteArray::writeStringWithoutLength(const std::string& value){
    write(value.c_str(), value.size()); 
}


//读取int8_t类型的数据
//getReadSize() >= sizeof(int8_t)
//m_position += sizeof(int8_t);
//如果getReadSize() < sizeof(int8_t) 抛出 std::out_of_range
int8_t  ByteArray::readFint8(){
    int8_t v;
    read(&v, sizeof(v));
    return v;
}
uint8_t  ByteArray::readFuint8(){
    uint8_t v;
    read(&v, sizeof(v));
    return v;
}

#define XX(type) \
	type v; \
	read(&v, sizeof(v)); \
	if(m_endian == SYLAR_BYTE_ORDER) { \
		return v; \
	} else { \
		return byteswap(v); \
	}

	int16_t  ByteArray::readFint16() {
		XX(int16_t);
	}
	uint16_t ByteArray::readFuint16() {
		XX(uint16_t);
	}

	int32_t  ByteArray::readFint32() {
		XX(int32_t);
	}

	uint32_t ByteArray::readFuint32() {
		XX(uint32_t);
	}

	int64_t  ByteArray::readFint64() {
		XX(int64_t);
	}

	uint64_t ByteArray::readFuint64() {
		XX(uint64_t);
	}

#undef XX

//读取有符号Varint32类型的数据
//getReadSize() >= 有符号Varint32实际占用内存
//m_position += 有符号Varint32实际占用内存
//如果getReadSize() < 有符号Varint32实际占用内存 抛出 std::out_of_range
int32_t  ByteArray::readInt32(){
    return DecodeZigzag32(readUint32());
}

//读取无符号Varint32类型的数据
//getReadSize() >= 无符号Varint32实际占用内存
//m_position += 无符号Varint32实际占用内存
//如果getReadSize() < 无符号Varint32实际占用内存 抛出 std::out_of_range
uint32_t ByteArray::readUint32(){
    uint32_t result = 0;
    for(int i = 0; i < 32; i += 7) {
        uint8_t b = readFuint8();
        if(b < 0x80) {     //没有下一个字节
            result |= ((uint32_t)b) << i;
            break;
        } else {
            result |= (((uint32_t)(b & 0x7f)) << i);
        }
    }
    return result;
}
int64_t  ByteArray::readInt64(){
    return DecodeZigzag64(readUint64());
}
uint64_t ByteArray::readUint64(){
    uint64_t result = 0;
    for(int i = 0; i < 64; i += 7) {
        uint8_t b = readFuint8();
        if(b < 0x80) {     //没有下一个字节
            result |= ((uint64_t)b) << i;
            break;
        } else {
            result |= (((uint64_t)(b & 0x7f)) << i);
        }
    }
    return result;
}

//读取float类型的数据
//getReadSize() >= sizeof(float)
//m_position += sizeof(float);
//如果getReadSize() < sizeof(float) 抛出 std::out_of_range
float ByteArray::readFloat(){
    uint32_t v = readFuint32();
    float value;
    memcpy(&value, &v, sizeof(v));
    return value;
}

//读取double类型的数据
//getReadSize() >= sizeof(double)
//m_position += sizeof(double);
//如果getReadSize() < sizeof(double) 抛出 std::out_of_range
double ByteArray::readDouble(){
    uint64_t v = readFuint64();
    double value;
    memcpy(&value, &v, sizeof(v));
    return value;
}

//读取std::string类型的数据,用uint16_t作为长度
//getReadSize() >= sizeof(uint16_t) + size
//m_position += sizeof(uint16_t) + size;
//如果getReadSize() < sizeof(uint16_t) + size 抛出 std::out_of_range
std::string ByteArray::readStringF16(){
    uint16_t len = readFuint16();   //先读uint16的string长度
    std::string buff;               //再读入到缓冲区
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}
std::string ByteArray::readStringF32(){
    uint32_t len = readFuint32();
    std::string buff;
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}
std::string ByteArray::readStringF64(){
    uint64_t len = readFuint64();
    std::string buff;
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}

//读取std::string类型的数据,用无符号Varint64作为长度
//getReadSize() >= 无符号Varint64实际大小 + size
//m_position += 无符号Varint64实际大小 + size;
//如果getReadSize() < 无符号Varint64实际大小 + size 抛出 std::out_of_range
std::string ByteArray::readStringVint(){
    	uint64_t len = readUint64();
		std::string buff;
		buff.resize(len);
		read(&buff[0], len);
		return buff;
}

/**
 * @brief 清空bytearray,只保留一个节点
 * 
 */
void ByteArray::clear(){
    m_position= m_size= 0;
    m_capacity = m_capacity;
    Node* tmp = m_root->next;
    while(tmp){
        m_cur = tmp;
        tmp = tmp->next;
        delete m_cur;
    }
    m_cur = m_root;
    m_root->next = nullptr;
}

/**
 * @brief 写入size长度
 * m_position += size, 如果m_position > m_size 则 m_size = m_position
 * 当前操作位置，当前节点位置，当前节点剩余容量，写入位置
 * @param buf 内存缓存指针
 * @param size 
 */
void ByteArray::write(const void* buf, size_t size){
    if(size == 0) {
        return;
    }
    addCapacity(size);

    size_t npos = m_position % m_baseSize;   // 当前节点位置
    size_t ncap = m_cur->size - npos;        // 当前节点的容量
    size_t bpos = 0;

    while(size > 0) {
        if(ncap >= size) { 
            memcpy(m_cur->ptr + npos, (const char*)buf + bpos, size);
            if(m_cur->size == (npos + size)) {
                m_cur = m_cur->next;  // 当前节点装满移到下一个节点
            }
            m_position += size;
            bpos += size;
            size = 0;
        } else {
            // 要写入的数据比当前节点容量大，先把当前节点写完
            memcpy(m_cur->ptr + npos, (const char*)buf + bpos, ncap);
            m_position += ncap;
            bpos += ncap;
            size -= ncap;
            m_cur = m_cur->next;
            ncap = m_cur->size;
            npos = 0;
        }
    }

    if(m_position > m_size) {
        m_size = m_position;
    }
}

/**
 * @brief 读取size长度的数据
 * m_position += size, 如果m_position > m_size 则 m_size = m_position
 * 如果getReadSize() < size 则抛出 std::out_of_range
 * @param buf 
 * @param size 
 */
void ByteArray::read(void* buf, size_t size){
    if(size > getReadSize()) {   // 超出了可读长度
        throw std::out_of_range("not enough len");
    }

    size_t npos = m_position % m_baseSize;
    size_t ncap = m_cur->size - npos;
    size_t bpos = 0;
    while(size > 0) {
        if(ncap >= size) {
            memcpy((char*)buf + bpos, m_cur->ptr + npos, size);
            if(m_cur->size == (npos + size)) {
                m_cur = m_cur->next;
            }
            m_position += size;
            bpos += size;
            size = 0;
        } else {
            memcpy((char*)buf + bpos, m_cur->ptr + npos, ncap);
            m_position += ncap;
            bpos += ncap;
            size -= ncap;
            m_cur = m_cur->next;
            ncap = m_cur->size;
            npos = 0;
        }
    }
}

/**
 * @brief 读取position位置size长度的数据, 不改变m_posi的位置
 * 如果 (m_size - position) < size 则抛出 std::out_of_range
 * @param buf 
 * @param size 
 * @param position 
 */
void ByteArray::read(void* buf, size_t size, size_t position) const{
    if(size > (m_size - position)) {
        throw std::out_of_range("not enough len");
    }

    size_t npos = position % m_baseSize;
    size_t ncap = m_cur->size - npos;
    size_t bpos = 0;
    Node* cur = m_cur;
    while(size > 0) {
        if(ncap >= size) {
            memcpy((char*)buf + bpos, cur->ptr + npos, size);
            if(cur->size == (npos + size)) {
                cur = cur->next;
            }
            position += size;
            bpos += size;
            size = 0;
        } else {
            memcpy((char*)buf + bpos, cur->ptr + npos, ncap);
            position += ncap;
            bpos += ncap;
            size -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
    }
}

/**
 * @brief 设置ByteArray当前位置
 * 如果m_position > m_size 则 m_size = m_position
 * 如果m_position > m_capacity 则抛出 std::out_of_range
 * @param v 
 */
void ByteArray::setPosition(size_t v){
    if(v > m_capacity) {
        throw std::out_of_range("set_position out of range");
    }
    m_position = v;
    if(m_position > m_size) {
        m_size = m_position;
    }
    m_cur = m_root;
    // 根据posi确定当前节点的位置
    while(v > m_cur->size) {
        v -= m_cur->size;
        m_cur = m_cur->next;
    }
    if(v == m_cur->size) {
        m_cur = m_cur->next;
    }
}

/**
 * @brief 把ByteArray的数据写入到文件中name 文件名
 * 如果数据有问题可以写到文件里看一看
 * @param name 
 * @return true 
 * @return false 
 */
bool ByteArray::writeToFile(const std::string& name) const{
		std::ofstream ofs;
		ofs.open(name, std::ios::trunc | std::ios::binary); 
		if(!ofs) {
			SYLAR_LOG_ERROR(g_logger) << "writeToFile name=" << name
				<< " error , errno=" << errno << " errstr=" << strerror(errno);
			return false;
		}

		int64_t read_size = getReadSize();
		int64_t pos = m_position;
		Node* cur = m_cur;

		while(read_size > 0) {
			int diff = pos % m_baseSize;
			int64_t len = (read_size > (int64_t)m_baseSize ? m_baseSize : read_size) - diff;
			ofs.write(cur->ptr + diff, len);
			cur = cur->next;
			pos += len;
			read_size -= len;
		}

		return true;
}

//从文件中读取数据 name 文件名
bool ByteArray::readFromFile(const std::string& name){
    std::ifstream ifs;
    ifs.open(name, std::ios::binary);
    if(!ifs) {
        SYLAR_LOG_ERROR(g_logger) << "readFromFile name=" << name
            << " error, errno=" << errno << " errstr=" << strerror(errno);
        return false;
    }

    std::shared_ptr<char> buff(new char[m_baseSize], [](char* ptr) { delete[] ptr;});
    while(!ifs.eof()) {
        ifs.read(buff.get(), m_baseSize);   // 读入m_baseSize个字节到buff
        // gcount()返回上一次输入操作被读入的字符的数目
        write(buff.get(), ifs.gcount());    // 写入到内存块
    }
    return true;
}


//是否是小端
bool ByteArray::isLittleEndian() const{
	return m_endian == SYLAR_LITTLE_ENDIAN;
}

void ByteArray::setIsLittleEndian(bool val) {
    if(val) {
        m_endian = SYLAR_LITTLE_ENDIAN;
    } else {
        m_endian = SYLAR_BIG_ENDIAN;
    }
}


// 将ByteArray里面的数据[m_position, m_size)转成std::string
std::string ByteArray::toString() const{
    std::string str;
    str.resize(getReadSize());
    if(str.empty()){
        return str;
    }
    read(&str[0], str.size(), m_position);
    return str;
}

//将ByteArray里面的数据[m_position, m_size)转成16进制的std::string(格式:FF FF FF)
std::string ByteArray::toHexString() const{
    std::string str = toString();
    std::stringstream ss;

    for(size_t i = 0; i < str.size(); ++i) {
        if(i > 0 && i % 32 == 0) {
            ss << std::endl;
        }
        ss << std::setw(2) << std::setfill('0') << std::hex
            << (int)(uint8_t)str[i] << " ";
    }

    return ss.str();
}

/**
 * @brief 获取可读取的缓存,保存成iovec数组
 * 
 * @param buffers buffers 保存可读取数据的iovec数组
 * @param len 读取数据的长度,如果len > getReadSize() 则 len = getReadSize()
 * @return uint64_t 实际数据的长度
 */
uint64_t ByteArray::getReadBuffers(std::vector<iovec>& buffers, uint64_t len) const{
    len = len > getReadSize() ? getReadSize() : len;
    if(len == 0) {
        return 0;
    }

    uint64_t size = len;

    size_t npos = m_position % m_baseSize;
    size_t ncap = m_cur->size - npos;
    struct iovec iov;
    Node* cur = m_cur;

    while(len > 0) {
        if(ncap >= len) {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = len;
            len = 0;
        } else {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = ncap;
            len -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
        buffers.push_back(iov);
    }
    return size;
}

/**
 * @brief 获取可读取的缓存,保存到iovec数组,从position位置开始
 * struct iovec{
 *      void * iov_base;
 *      size_t iov_len;
 * }
 * @param buffers 保存可读取数据的iovec数组
 * @param len 读取数据的长度,如果len > getReadSize() 则 len = getReadSize()
 * @param position 读取数据的位置
 * @return uint64_t 实际数据的长度
 */
uint64_t ByteArray::getReadBuffers(std::vector<iovec>& buffers, uint64_t len, uint64_t position) const{
    len = len > getReadSize() ? getReadSize() : len;
    if(len == 0) {
        return 0;
    }

    uint64_t size = len;

    size_t npos = position % m_baseSize;
    size_t count = position / m_baseSize;
    Node* cur = m_root; 
    while(count > 0) {
        cur = cur->next;    // 找到当前posi的内存块
        --count;
    }

    size_t ncap = cur->size - npos;  // 当前内存块剩余刻度内容
    struct iovec iov;
    while(len > 0) {
        if(ncap >= len) {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = len;
            len = 0;
        } else {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = ncap;
            len -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
        buffers.push_back(iov);
    }
    return size;
}

/**
 * @brief 获取可写入的缓存,保存到iovec数组
 * 如果(m_position + len) > m_capacity 则 m_capacity扩容N个节点以容纳len长度
 * @param buffers 保存可写入的内存的iovec数组
 * @param len 写入缓冲区的总长度
 * @return uint64_t 实际的长度
 */
uint64_t ByteArray::getWriteBuffers(std::vector<iovec>& buffers, uint64_t len){
    if(len == 0) {
        return 0;
    }
    addCapacity(len);   //扩容
    uint64_t size = len;

    size_t npos = m_position % m_baseSize;
    size_t ncap = m_cur->size - npos;
    struct iovec iov;
    Node* cur = m_cur;
    while(len > 0) {
        if(ncap >= len) {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = len;
            len = 0;
        } else {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = ncap;

            len -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
        buffers.push_back(iov);
    }
    return size;
}


//扩容ByteArray,使其可以容纳size个数据(如果原本可以可以容纳,则不扩容)
void ByteArray::addCapacity(size_t size){
    if(size == 0) {
        return;
    }
    size_t old_cap = getCapacity();
    if(old_cap >= size) {
        return;
    }

    size = size - old_cap;
    size_t count = ceil(1.0 * size / m_baseSize);
    Node* tmp = m_root;
    while(tmp->next) {
        tmp = tmp->next;
    }

    Node* first = NULL;
    for(size_t i = 0; i < count; ++i) {
        tmp->next = new Node(m_baseSize);
        if(first == NULL) {
            first = tmp->next;
        }
        tmp = tmp->next;
        m_capacity += m_baseSize;
    }

    if(old_cap == 0) {
        m_cur = first;
    }
}



}